package com.xxl.sso.core.filter;

import com.alibaba.algo.cooperation.common.BaseResult;
import com.alibaba.fastjson.JSON;
import com.xxl.sso.core.conf.Conf;
import com.xxl.sso.core.login.SsoWebLoginHelper;
import com.xxl.sso.core.path.impl.AntPathMatcher;
import com.xxl.sso.core.user.XxlSsoUser;
import com.xxl.sso.core.util.ResponseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * web sso filter
 *
 * @author xuxueli 2018-04-03
 */
public class XxlSsoWebFilter extends HttpServlet implements Filter {
    private static Logger logger = LoggerFactory.getLogger(XxlSsoWebFilter.class);

    private static final AntPathMatcher antPathMatcher = new AntPathMatcher();

    private String ssoServer;
    private String logoutPath;
    private String excludedPaths;
    private XxlSsoProperties xxlSsoProperties;

    public XxlSsoWebFilter (XxlSsoProperties xxlSsoProperties){
        this.xxlSsoProperties = xxlSsoProperties;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        ssoServer = filterConfig.getInitParameter(Conf.SSO_SERVER);
        logoutPath = filterConfig.getInitParameter(Conf.SSO_LOGOUT_PATH);
        excludedPaths = filterConfig.getInitParameter(Conf.SSO_EXCLUDED_PATHS);

        logger.info("XxlSsoWebFilter init,xxlSsoProperties:{}",JSON.toJSONString(xxlSsoProperties));
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;



        logger.info("-过滤请求--->{}", request.toString());
        logger.info("--过滤参数--->{}", request.getParameterMap().toString());
        logger.info("-过滤响应--->{}", response.toString());


        // make url
        String servletPath = req.getServletPath();

        logger.info("servlet path={}",servletPath);

        // excluded path check
        if (excludedPaths!=null && excludedPaths.trim().length()>0) {
            for (String excludedPath:excludedPaths.split(",")) {
                String uriPattern = excludedPath.trim();

                // 支持ANT表达式
                if (antPathMatcher.match(uriPattern, servletPath)) {
                    // excluded path, allow
                    chain.doFilter(request, response);
                    return;
                }

            }
        }

        // logout path check
        if (logoutPath!=null
                && logoutPath.trim().length()>0
                && logoutPath.equals(servletPath)) {
            logger.info("######################XxlSsoWebFilter logoutPath:{}",logoutPath);
            // remove cookie
            SsoWebLoginHelper.logout(req, res);

            // redirect logout
            String logoutPageUrl = ssoServer.concat(Conf.SSO_LOGOUT);
            //判断业务系统是否是前后端分离
            if (xxlSsoProperties.getRedirect()){
                Map<String,String> dataMap = new HashMap<>();
                dataMap.put("loginPageUrl",logoutPageUrl+"?redirect_url=");
                ResponseUtils.writeResponse(res,BaseResult.buildError(Conf.SSO_LOGIN_FAIL_RESULT.getCode(),Conf.SSO_LOGIN_FAIL_RESULT.getMsg(),dataMap));
                return;
            }
            res.sendRedirect(logoutPageUrl);
            return;
        }

        // valid login user, cookie + redirect
        XxlSsoUser xxlUser = SsoWebLoginHelper.loginCheck(req, res);

        // valid login fail
        if (xxlUser == null) {
            String header = req.getHeader("content-type");
            boolean isJson=  header!=null && header.contains("json");

            if (isJson) {
                // json msg
                res.setContentType("application/json;charset=utf-8");
                Map<String,String> dataMap = new HashMap<>();
                dataMap.put("loginPageUrl", ssoServer
                        .concat(Conf.SSO_LOGIN) + "?" + Conf.REDIRECT_URL + "=" + xxlSsoProperties.getClientWebUrl() + xxlSsoProperties.getReceiveSession() + "&"
                        + Conf.TO_URL + "=");
                ResponseUtils.writeResponse(res, BaseResult.buildError(Conf.SSO_LOGIN_FAIL_RESULT.getCode(), Conf.SSO_LOGIN_FAIL_RESULT.getMsg(),dataMap));
                return;
            } else {
                // total link
                String link = req.getRequestURL().toString();
                // redirect logout
                String loginPageUrl = ssoServer.concat(Conf.SSO_LOGIN)
                        + "?" + Conf.REDIRECT_URL + "=" + link;
                //判断业务系统是否是前后端分离
                if (xxlSsoProperties.getRedirect()){
                    res.getWriter().println(
                            "{\"code\":" + Conf.SSO_LOGIN_FAIL_RESULT.getCode() + ", \"msg\":\"" + Conf.SSO_LOGIN_FAIL_RESULT.getMsg() + "\", \"loginPageUrl\":\"" + ssoServer
                                    .concat(Conf.SSO_LOGIN) + "?" + Conf.REDIRECT_URL + "="+xxlSsoProperties.getClientWebUrl()+xxlSsoProperties.getReceiveSession()+"&"+Conf.TO_URL+"=" + "\"}");
                    return;
                }
                res.sendRedirect(loginPageUrl);
                return;
            }
        }

        // ser sso user
        request.setAttribute(Conf.SSO_USER, xxlUser);


        // already login, allow
        chain.doFilter(request, response);
        return;
    }

}
